package me.jzn.alib.pref;

import android.content.Context;
import android.content.SharedPreferences;

import androidx.security.crypto.EncryptedSharedPreferences;
import androidx.security.crypto.MasterKey;

import java.io.IOException;
import java.security.GeneralSecurityException;

import me.jzn.alib.ALib;
import me.jzn.core.exceptions.ShouldNotRunHereException;
import me.jzn.core.exceptions.UnableToRunHereException;

/**
 * 采用masterKey来
 * implementation rootProject.ext.lib["x-security"]
 */
public class MkPref extends Pref {
    private boolean mLockRequired;

    public MkPref(String name) throws MasterKeyChangedExeption, UnsupportedMkException {
        super(name, createCipherPrefNoLockRequired(ALib.app(), name));
        mLockRequired = false;
    }

    public MkPref(String name, boolean lockRequired) throws UnsupportedMkException, MasterKeyChangedExeption {
        super(name, createCipherPref(ALib.app(), name, lockRequired));
        this.mLockRequired = lockRequired;
    }

    @Override
    public void rename(String newName) {
        try {
            super.rename(newName, createCipherPrefNoException(ALib.app(), newName, mLockRequired));
        } catch (UnsupportedMkException e) {
            throw new ShouldNotRunHereException("在构造函数中已经处理过了", e);
        }
    }

    private static SharedPreferences createCipherPrefNoException(Context ctx, String name, boolean lockRequired) throws UnsupportedMkException {
        try {
            return createCipherPref(ctx, name, lockRequired);
        } catch (MasterKeyChangedExeption e) {
            throw new UnableToRunHereException(e);
        }
    }

    private static SharedPreferences createCipherPrefNoLockRequired(Context ctx, String name) throws MasterKeyChangedExeption, UnsupportedMkException {
        return createCipherPref(ctx, name, false);
    }

    private static SharedPreferences createCipherPref(Context ctx, String name, boolean lockRequried) throws MasterKeyChangedExeption, UnsupportedMkException {
        MasterKey masterKey = getMasterKey(ctx, lockRequried);
        try {
            return EncryptedSharedPreferences.create(ctx, name, masterKey, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM);
        } catch (GeneralSecurityException e) {
            throw new ShouldNotRunHereException(e);
        } catch (IOException e) {
            if (e.getClass().getSimpleName().equals("InvalidProtocolBufferException")) {
                throw new MasterKeyChangedExeption(e);
            }
            throw new ShouldNotRunHereException(e);
        }
    }

    private static MasterKey getMasterKey(Context ctx, boolean pinRequired) throws UnsupportedMkException {
        //结论，在安卓6(23)上测试与oppo14(34)上测试,StrongBox无论是否设置，总是false，与系统应该有关。
        //auth设置啥就是啥，与是否有锁屏也无关.
        //keystorebacked总是返回true
        MasterKey.Builder builder = new MasterKey.Builder(ctx).setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
                //与系统有关，28以上支持
//                .setRequestStrongBoxBacked(true)
                .setUserAuthenticationRequired(pinRequired);
        try {
            MasterKey mk = builder.build();
            return mk;
        } catch (GeneralSecurityException e) {
            //有用户报错，尚未浮现
            //.GeneralSecurityException: Keystore key generation failed
            //.ProviderException: Keystore key generation failed
            //.KeyStoreException: Invalid key blob
            // 0: While generating Key without explicit attestation key.
            //    1: Error::Km(ErrorCode(-33)))
            throw new UnsupportedMkException(e);
        } catch (IOException e) {
            throw new ShouldNotRunHereException("获取masterKey 失败", e);
        }
    }

    public static class MasterKeyChangedExeption extends Exception {
        public MasterKeyChangedExeption(IOException e) {
            super("masterKey变了，APP可能被卸载过", e);
        }
    }

    public static class UnsupportedMkException extends Exception {
        public UnsupportedMkException(GeneralSecurityException e) {
            //.GeneralSecurityException: Keystore key generation failed
            //ProviderException: Keystore key generation failed
            //KeyStoreException: Invalid key blob (internal Keystore code: -33 message: In generate_key.
            // 0: While generating Key without explicit attestation key.
            // 1: Error::Km(ErrorCode(-33)))
            super("系统锁屏才能可以使用强MasterKey", e);
        }
    }
}
